<?php
/**
 *
 * 错误码  -205xxx
 * 会话服务
 */

namespace common\service;

use common\exception\LogicException;
use common\model\ChatModel;
use common\model\ChatUnreadMessageModel;
use common\model\ChatUserModel;
use common\model\DepartmentModel;
use common\model\MediaModel;
use common\model\MessageModel;
use common\model\TenantModel;
use common\model\TenantUserModel;
use common\model\UserModel;
use malkusch\lock\mutex\PHPRedisMutex;
use support\bootstrap\Redis;
use support\ErrorCode;
use support\SingletonTrait;
use teamones\Request;
use think\Exception;
use think\Model;
use think\model\RelationModel;
use think\Tree;
use Webman\Stomp\Client;

class ChatService
{
    /** @var MessageModel */
    private $messageModel;

    // 单例工具类
    use SingletonTrait;

    public function __construct()
    {
        $this->messageModel = model(MessageModel::class);
    }

    /**
     * 获取用户成员信息
     * @param array $chatIds
     * @return mixed
     */
    public function getChatUserData($chatIds = [])
    {
        $chatUserModel = model(ChatUserModel::class);
        $chatUserData = $chatUserModel->where([
            'chat_global_id' => ['IN', join(',', $chatIds)],
            'is_leave' => "no",
        ])->select();
        return $chatUserData;
    }


    /**
     * @param $id
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function getChatDataById($id)
    {
        $oldData = ChatService::getInstance()->getChatDetail(['id' => $id]);
        return !empty($oldData) ? $oldData : [];
    }

    /**
     * 发送更改群名的消息
     * @param $data
     * @param $oldData
     * @param $userId
     * @throws \Exception
     */
    public function checkChatName($data, $oldData, $userId)
    {
        $oldName = !empty($oldData) ? $oldData['name'] : "";
        if (!empty($data['id']) && !empty($data['name']) && $oldName !== $data['name']) {
            $oldData['name'] = $data['name'];
            (new MessageService())->pushUpdateChatNameMessage($oldData, $userId);
        }
    }

    /**
     * 更改群名时检测是否时群主
     * @param $data
     * @param $oldData
     * @param $userId
     */
    public function checkChatNameIsAdmin($data, $oldData, $userId)
    {
        $oldName = !empty($oldData) ? $oldData['name'] : "";
        if (!empty($data['name']) && $oldName !== $data['name']) {
            $chatUserMine = model(ChatUserModel::class)->where(['chat_global_id' => $oldData['global_id'], 'user_id' => $userId])->find();
            if (empty($chatUserMine) || (int)$chatUserMine['is_admin'] !== 1) {
                throw_strack_exception("you are`nt admin,can`t change chat name", ErrorCode::ONLY_ADMINISTRATORS_CAN_CHANGE_CHAT_NAME);
            }
        }
    }


    /**
     * 按Key索引
     * @param $data
     * @param $key
     * @return array
     */
    protected function generateIndexByKey($data, $key)
    {
        $newData = [];
        foreach ($data as $item) {
            $newData[$item[$key]][] = $item;
        }
        return $newData;
    }

    /**
     * 获取用户姓名和头像
     * @param array $userIds
     * @return mixed
     */
    public function getChatUserInfo($userIds = [])
    {
        $userInfo = model(UserModel::class)
            ->alias('user')
            ->join('LEFT JOIN media ON media.link_id=user.id AND media.type="thumb" AND media.module="user"')
            ->field('user.id,user.name,media.thumb,user.phone,media.thumb as avatar,user.id as strack_open_id,user.is_system')
            ->where(['user.id' => ['IN', join(',', $userIds)]])
            ->select();


        return $userInfo;
    }

    /**
     * 获取私聊对方ID
     * @param $currentUserId
     * @param $globalId
     * @return mixed
     */
    protected function getPrivateChatOtherId($currentUserId, $globalId)
    {
        $userIds = explode('&', $globalId);
        foreach ($userIds as $userId) {
            if ((int)$userId !== (int)$currentUserId) {
                return $userId;
            }
        }
    }

    /**
     * 获取用户指定会话未读消息
     * @param $currentUserId
     * @param array $chatIds
     * @return mixed
     */
    public function getChatUnreadMessageData($currentUserId, $chatIds = [])
    {
        $chatUnreadMessageModel = model(ChatUnreadMessageModel::class);
        return $chatUnreadMessageModel->where([
            'chat_global_id' => ['IN', join(',', $chatIds)],
            'user_id' => $currentUserId
        ])->select();
    }

    /**
     * 获取多个用户头像
     * @param $userID
     * @return array
     */
    public function getUsersAvatar($userID)
    {
        $reData = [];

        $mediaModel = model(MediaModel::class);

        $userImage = $mediaModel->field('link_id,thumb')
            ->where([
                'link_id' => ["IN", join(',', $userID)],
                'module' => 'user',
                'type' => 'thumb'
            ])
            ->select();

        foreach ($userImage as $key => $value) {
            $reData[$value['link_id']] = $value['thumb'];
        }
        return $reData;
    }

    /**
     * @param $currentUserId
     * @param $userChat
     * @param $charUserDataMap
     * @param $userInfoMap
     * @return array
     */
    protected function formatChatData($currentUserId, $userChat, $charUserDataMap, $userInfoMap)
    {
        // 最后聊天记录
        $tempData = [
            'id' => $userChat['chat_id'],
            'type' => $userChat['type'],
            'chat_global_id' => $userChat['global_id'],
            'config' => json_decode($userChat['config'], true),
            'avatar' => [],
            'count' => count($charUserDataMap[$userChat['global_id']] ?? []),
            'last_message' => [],
            'unread_count' => 0,
            "name" => "",
        ];
        $tempData = array_merge($userChat, $tempData);

        switch ($userChat['type']) {
            case 'system':
                // 系统组
                $tempData['name'] = $userChat['name'];
                $tempData['avatar'] = [""];
                break;
            case 'group':
                // 聊天群组
                $tempData['name'] = $userChat['name'];
                $count = 0;
                foreach ($charUserDataMap[$userChat['global_id']] ?? [] as $chatItem) {
                    if (isset($userInfoMap[$chatItem['user_id']])) {
                        $tmpAvatar = !empty($userInfoMap[$chatItem['user_id']]['thumb']) ? $userInfoMap[$chatItem['user_id']]['thumb'] : "";
                        $tempData['avatar'][] = $tmpAvatar;
                        $tempData['chat_icon_data'][] = [
                            "id" => $chatItem['user_id'],
                            "name" => $userInfoMap[$chatItem['user_id']]['name'] ?? "佚名",
                            "avatar" => $tmpAvatar,
                        ];
                        $count++;
                        if ($count === 9) {
                            break;
                        }
                    } else {
                        continue;
                    }
                };
                break;
            case 'one2one':
            default:
                // 一对一聊天
                $otherUserId = $this->getPrivateChatOtherId($currentUserId, $userChat['global_id']);

                if (!empty($otherUserId) && isset($userInfoMap[$otherUserId])) {
                    $tempData['name'] = $userInfoMap[$otherUserId]['name'];
                    $tmpAvatar = empty($userInfoMap[$otherUserId]['thumb']) ? "" : $userInfoMap[$otherUserId]['thumb'];
                    $tempData['avatar'] = [$tmpAvatar];

                    $tempData['chat_icon_data'][] = [
                        "id" => $otherUserId,
                        "name" => $userInfoMap[$otherUserId]['name'] ?? "",
                        "avatar" => $tmpAvatar,
                    ];
                } else {
                    $tempData['name'] = "佚名";
                    $tempData['avatar'] = [""];
                    $tempData['chat_icon_data'][] = [
                        "name" => $userChat['name'],
                        "avatar" => "",
                    ];

                }
                //如果用户为系统用户 那么就修正当前会话为system会话
                $tempData['is_system'] = $userInfoMap[$otherUserId]['is_system'] ?? "no";
                break;
        }
        return $tempData;
    }

    /**
     * 创建会话
     * @param $currentUser
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function createChat($currentUser, $param)
    {
        $globalId = create_uuid();
        if (count($param['data']['receiver']) === 1) {
            if ($param['data']['receiver'][0] == $currentUser) {
                throw new LogicException("cant` creat chat with yourself", ErrorCode::UNABLE_TO_CHAT_WITH_YOURSELF);
            }
            $type = 'one2one';
            if ($currentUser > $param['data']['receiver'][0]) {
                $globalId = $param['data']['receiver'][0] . '&' . $currentUser;
            } else {
                $globalId = $currentUser . '&' . $param['data']['receiver'][0];
            }
            $name = '私聊';
        } else {
            $type = 'group';
            $name = '群聊';
        }

        if (!empty($param['data']['name'])) {
            $name = $param['data']['name'];
        }

        $chatModel = model(ChatModel::class);
        $chatUserModel = model(ChatUserModel::class);

        $extraData = $param['data']['extra_data'] ?? [];
        $resData = ChatService::getInstance()->getChatDetail(['global_id' => $globalId]);

        if (empty($resData)) {
            // 不存在会话创建
            $data = [
                'data' => [//会话基础数据
                        'name' => $name,
                        'type' => $type,
                        'created_by' => $currentUser,
                        'global_id' => $globalId
                    ] + $extraData,
                'receiver' => $param['data']['receiver'],
                'sender' => $currentUser,
                'global_id' => $globalId
            ];

            //发送者合并至接受者成为会话成员
            $chatUsers = [];
            array_push($data['receiver'], $data['sender']);
            $data['receiver'] = array_unique($data['receiver']);

            //一对一
            if ($type == 'one2one') {
                $chatUsers[] = [
                    'chat_global_id' => $data['global_id'],
                    'user_id' => $data['receiver'][0],
                    'to_user_id' => $data['receiver'][1],
                    'is_admin' => 0,
                    'join_at' => time()
                ];

                $chatUsers[] = [
                    'chat_global_id' => $data['global_id'],
                    'user_id' => $data['receiver'][1],
                    'to_user_id' => $data['receiver'][0],
                    'is_admin' => 0,
                    'join_at' => time()
                ];

            } else {
                foreach ($data['receiver'] as $userId) {
                    $isAdmin = 0;
                    //如果成员等于创建者且会话为群组，则为管理员
                    if ($userId === $data['sender'] && count($data['receiver']) > 1) {
                        $isAdmin = 1;
                    }
                    $chatUsers[] = [
                        'chat_global_id' => $data['global_id'],
                        'user_id' => $userId,
                        'is_admin' => $isAdmin,
                        'join_at' => time()
                    ];
                }
            }

            // 开启事务处理
            $chatModel->startTrans();
            try {
                // 新增会话基础信息
                $resData = $chatModel->addItem($data['data']);
                if (!$resData) {
                    throw new LogicException($chatModel->getError(), $chatModel->getErrorCode());
                }

                $chatUserResult = $chatUserModel->addAll($chatUsers);
                if (!$chatUserResult) {
                    throw new LogicException($chatUserModel->getError(), $chatUserModel->getErrorCode());
                }
                $chatModel->commit();
                try {
                    $messageService = new MessageService();
                    $messageService->pushNewChatMessage($resData['id'], $data['receiver'], $currentUser);
                } catch (\Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
            } catch (\Exception $e) {
                $chatModel->rollback();
                throw_strack_exception($e->getMessage(), $e->getCode());
            }
        }

        // 获取当前用户关联的会话信息
        $userChat = $chatUserModel->alias('chat_user')
            ->join('LEFT JOIN chat ON chat.global_id = chat_user.chat_global_id')
            ->field('chat.name,chat.id as chat_id,chat.global_id,chat.type,chat_user.user_id,chat_user.chat_global_id,chat_user.config')
            ->where([
                'chat.id' => $resData['id'],
                'chat_user.user_id' => $currentUser
            ])
            ->find();

        // 会话ids
        $chatIds = [$userChat['global_id']];


        // 会话成员信息
        $chatUserData = $this->getChatUserData($chatIds);
        $charUserDataMap = [];

        if (!empty($chatUserData)) {
            $charUserDataMap = $this->generateIndexByKey($chatUserData, 'chat_global_id');
        }


        // 获取会话成员信息（头像、名称）
        $userInfoMap = [];
        if (!empty($chatUserData)) {
            $chatUserIds = array_column($chatUserData, 'user_id', 'user_id');
            $userInfo = $this->getChatUserInfo($chatUserIds);

            $userInfoMap = array_column($userInfo, null, 'id');
        }

        $formatData = $this->formatChatData($currentUser, $userChat, $charUserDataMap, $userInfoMap);
        return $formatData;
    }

    /**
     * 包含可传入部门id
     * @param $currentUser
     * @param $tenantId
     * @param $param
     * @return array
     * @throws \Throwable
     */
    public function createGroupChat($currentUser, $tenantId, $param)
    {
        $receiver = $param['data']['receiver'];
        $receiver = array_group_by($receiver, 'type');
        $userIds = [];
        if (!empty($receiver['user'])) {
            $userIds = array_unique(array_column($receiver['user'], 'id'));
        }

        if (!empty($receiver['department'])) {
            $departmentData = array_column($receiver['department'], 'id');

            $departmentList = model(DepartmentModel::class)
                ->where(["tenant_id" => $tenantId])
                ->field("id,name,parent_id")
                ->order(['id' => 'DESC'])
                ->select();

            $tree = new Tree("id", "parent_id");
            $tree->load($departmentList);

            //加入部门子集id
            $departmentIds = $departmentData;
            foreach ($departmentData as $departmentId) {
                $childrenDepartmentList = $tree->deepTree($departmentId);
                $tree->traverseTree($childrenDepartmentList, function (&$childrenDepartmentId) use ($departmentIds) {
                    if (!in_array($childrenDepartmentId, $departmentIds)) {
                        $departmentIds[] = $childrenDepartmentId;
                    }
                });
            }

            $departmentIds = array_unique($departmentIds);
            $departmentFilter = ["IN", $departmentIds];
            $userList = (new UserService())->getTenantDepartmentUserList($departmentFilter, $tenantId, false);
            $userListIds = array_column($userList, 'id');
            $userListIds = array_unique($userListIds);
            $userIds = array_merge($userIds, $userListIds);
        }

        if (!empty($userIds)) {
            $systemUsers = model(UserModel::class)->where(['is_system' => 'yes'])->field('id')->select();
            $systemUsers = array_column($systemUsers, 'id');
            $userIds = array_filter($userIds, function ($item) use ($currentUser, $systemUsers) {
                return $item != $currentUser && !empty($item) && !in_array($item, $systemUsers);
            });
            $userIds = array_values($userIds);

            $param['data']['receiver'] = $userIds;
            return $this->createChat($currentUser, $param);
        } else {
            return [];
        }

    }

    /**
     * 获取用户会话ids 通过用户名称模糊查询
     * @param $currentUserId
     * @param $name
     * @return array
     */
    protected function getUserChatGlobalIdsByName($currentUserId, $name)
    {
        $chatUserModel = model(ChatUserModel::class);
        $userChatGlobalIds = $chatUserModel->alias('chat_user')
            ->join('INNER JOIN user ON user.id = chat_user.to_user_id')
            ->where([
                'chat_user.user_id' => $currentUserId,
                'user.name' => ['LIKE', "%{$name}%"]
            ])
            ->field("chat_user.chat_global_id")
            ->select();

        return !empty($userChatGlobalIds) ? array_column($userChatGlobalIds, 'chat_global_id') : [];
    }

    /**
     * 获取当前登录用户会话列表
     * @param $currentUserId
     * @param $tenantId
     * @param $param
     * @return array[]
     * @throws Exception
     */
    public function getUserChatList($currentUserId, $tenantId, $param)
    {
        $chatUserModel = model(ChatUserModel::class);

        // 1、组装主表过滤条件
        $page = $param['param']['page'] ?? [1, 50];

        $queryFields = [
            "chat.name",
            "chat.id as chat_id",
            "chat.global_id",
            "chat.type",
            "chat.link_type",
            "chat.link_id",
            "chat_user.user_id",
            "chat_user.chat_global_id",
            "chat_user.config",
            "chat_user.mute",
            "chat_user.favorite",
            "chat.edited_at",
            "chat.chat_avatar_id"
        ];

        $filter = [
            'chat_user.user_id' => $currentUserId,
            'chat_user.is_leave' => "no",
            'chat.is_delete' => 'no',
            'chat.link_type' => ['NEQ', 'task_work_order'],
        ];

        $replyMessageList = [];
        $forwardMessageList = [];

        // 1.1、是否限制类型
        $chatType = '';
        if (!empty($param['param']['filter']['type'])) {
            $filter['chat.type'] = $param['param']['filter']['type'];
            $chatType = $filter['chat.type'];
        }

        // 1.2 按会话
        if (!empty($param['param']['filter']['name'])) {
            if ($chatType === 'one2one' || empty($chatType)) {
                // 如果会话查询类型为one2one，或者为空则组装人员查询条件
                $userChatGlobalIds = $this->getUserChatGlobalIdsByName($currentUserId, $param['param']['filter']['name']);
                if (!empty($userChatGlobalIds)) {
                    $filter['_complex'] = [
                        'chat.name' => ["Like", "%{$param['param']['filter']['name']}%"],
                        'chat.global_id' => ["IN", join(',', $userChatGlobalIds)],
                        '_logic' => 'or'
                    ];
                } else {
                    $filter['chat.name'] = ["Like", "%{$param['param']['filter']['name']}%"];
                }
            } else {
                $filter['chat.name'] = ["Like", "%{$param['param']['filter']['name']}%"];
            }
        }

        // 1.3 按会话ID
        if (!empty($param['param']['filter']['global_id'])) {
            $filter['chat.global_id'] = $param['param']['filter']['global_id'];
        }

        //排序 置顶/最新消息时间
        $order = $param['param']['order'] ?? ["chat_user.favorite asc", "chat.edited_at desc"];

        // 携带filter外的type参数需要将会话类型的限制清除
        if (!empty($param['param']['type'])) {
            unset($filter['chat.link_type']);
        }

        // 1.3 是否查询工单会话(默认不查询工单会话)
        if (!empty($param['param']['chat.link_type'])) {
            $filter['chat.link_type'] = $param['param']['chat.link_type'];
        }

        // 查询租户
        if (!empty($param['param']['chat.from_tenant_id'])) {
            $filter['chat.from_tenant_id'] = $param['param']['chat.from_tenant_id'];
        }
        // 1.4 查询指定工单会话
        if (!empty($param['param']['chat.link_id'])) {
            $filter['chat.link_id'] = $param['param']['chat.link_id'];
            // 2、查询主表及其关联表信息，获取当前用户关联的会话信息
            $userChatList = $chatUserModel->alias('chat_user')
                ->join('LEFT JOIN chat ON chat.global_id=chat_user.chat_global_id')
                ->field(implode(',', $queryFields))
                ->where($filter)
                ->order($order)
                ->select();
        } else if (!empty($param['param']['chat.link_type']) && $param['param']['chat.link_type'] == 'get_work_order_unread_chat') {
            $userChatList = $chatUserModel
                ->join("chat_unread_message as cum on cum.chat_global_id = chat_user.chat_global_id and cum.user_id = chat_user.user_id")
                ->join('chat on chat.global_id = cum.chat_global_id')
                ->where(['chat.link_type' => 'task_work_order', 'cum.user_id' => $currentUserId])
                ->where(['chat_user.is_leave' => 'no', 'chat.is_delete' => 'no'])
                ->page(0, 500)
                ->group('chat.global_id')
                ->field(implode(',', $queryFields))
                ->select();
        } else {
            // 2、查询主表及其关联表信息，获取当前用户关联的会话信息
            $userChatList = $chatUserModel->alias('chat_user')
                ->join('LEFT JOIN chat ON chat.global_id=chat_user.chat_global_id')
                ->field(implode(',', $queryFields))
                ->where($filter)
                ->page($page[0], $page[1])
                ->order($order)
                ->select();
        }
        // 查询会话头像
        $chatAvatarIds = array_column($userChatList, 'chat_avatar_id');
        $chatAvatarData = model(MediaModel::class)->where(['id' => ['IN', implode(',', $chatAvatarIds)]])->select();
        $chatAvatarList = array_column($chatAvatarData, null, 'id');
        // 3、统计未读消息条数 count，并拿到最新一条消息

        // 3.1、会话ids
        $chatIds = array_column($userChatList, 'global_id');

        // 3.2、未读消息的数量 TODO 数据量太大隐患
        $unReadMessageModel = model(ChatUnreadMessageModel::class);
//        $unreadCountList = $unReadMessageModel
//            ->join("chat_user on chat_unread_message.user_id = chat_user.user_id AND chat_unread_message.chat_global_id = chat_user.chat_global_id")
//            ->where([
//                'chat_unread_message.chat_global_id' => ['IN', join(',', $chatIds)],
//                'chat_unread_message.user_id' => $currentUserId
//            ])
//            ->where(['chat_user.mute'=>'no'])
//            ->field("chat_unread_message.chat_global_id")
//            ->select();
//
//        $unreadCount = [];
//        foreach ($unreadCountList as $unreadCountItem) {
//            if (!array_key_exists($unreadCountItem['chat_global_id'], $unreadCount)) {
//                $unreadCount[$unreadCountItem['chat_global_id']] = 1;
//            } else {
//                ++$unreadCount[$unreadCountItem['chat_global_id']];
//            }
//        }

        // 改用 group_by count(*) 统计, 缓存5秒
        $unreadCountList = $unReadMessageModel
            ->where([
                'chat_unread_message.chat_global_id' => ['IN', join(',', $chatIds)],
                'chat_unread_message.user_id' => $currentUserId
            ])
            ->field("chat_unread_message.chat_global_id,count(*) as count")
            ->group('chat_unread_message.chat_global_id')
            ->cache(5)
            ->select();

        $unreadCount = array_column($unreadCountList, 'count', 'chat_global_id');

        // 3.2 最后一条消息查询
        $lastMessageList = [];
        $unreadChatList = [];
        if (!empty($chatIds)) {
            $lastMessageIdList = $this->messageModel->where(['chat_global_id' => ['IN', $chatIds]])->field('max(id) as id')->group("chat_global_id")->select();
            $lastMessageIdList = array_column($lastMessageIdList, 'id');
            if (count($lastMessageIdList) > 0) {
                $lastMessageList = $this->messageModel->where(['id' => ['IN', $lastMessageIdList]])->field('id,chat_global_id,content_type,content,sent_at,sender,status,reply_message_id')->select();
                $lastMessageList = array_column($lastMessageList, null, 'chat_global_id');
            }
            // 处理工单助手的最后一条
            $workOrderAssistantChat = $this->getChatWithSystemNotifyUser($currentUserId, 'work_order_assistant');
            if (!empty($workOrderAssistantChat)) {
                if (in_array($workOrderAssistantChat['global_id'], $chatIds)) {
                    // 取出未读的工单会话
                    $this->getWorkOrderAssistantChatRelateInfo($currentUserId, $workOrderAssistantChat, $unreadCount, $lastMessageList, $unreadChatList);
                }
            }

        }

        if (!empty($param['param']['last_message_check'])) {
            // 转发消息到会话中需要检查会话信息以及最近一条消息内容，如果是回复消息需要返回被回复的消息体
            if ($lastMessageList) {
                $replyMessageIds = [];
                $tmpForwardMessageIds = [];
                $forwardMessageIds = [];
                foreach ($lastMessageList as $item) {
                    if (!empty($item['reply_message_id']) && $item['reply_message_id'] > 0) {
                        $replyMessageIds[] = $item['reply_message_id'];
                    }
                    $content = json_decode($item['content'], true);
                    if ($item['content_type'] == 'forward' && !empty($content['forward_message_ids'])) {
                        $tmpForwardMessageIds = explode(",", $content['forward_message_ids']);
                        sort($tmpForwardMessageIds); // 保存的消息ID顺序根据前端操作决定，需要按照正序排列
                        $tmpForwardMessageIds = array_slice($tmpForwardMessageIds, 0, 5);
                    }
                    $forwardMessageIds = array_merge($forwardMessageIds, $tmpForwardMessageIds);
                }
                if ($replyMessageIds) {
                    $replyMessageList = $this->messageModel->where(['id' => ['IN', implode(',', $replyMessageIds)]])->select();
                    $replyMessageList = array_column($replyMessageList, null, 'id');
                }
                if ($forwardMessageIds) {
                    $forwardMessageList = $this->messageModel->where(['id' => ['IN', implode(',', $forwardMessageIds)]])->select();
                    $forwardMessageList = array_column($forwardMessageList, null, 'id');
                    $forwardMessageSenderIds = array_column($forwardMessageList, 'sender');
                    // 获取消息发送人
                    if ($forwardMessageSenderIds) {
                        $forwardMessageSenderList = model(UserModel::class)->field('id,name')->where(['id' => ['IN', implode(',', $forwardMessageSenderIds)]])->select();
                        $forwardMessageSenderList = array_column($forwardMessageSenderList, 'name', 'id');
                    }
                }
            }
        }

        // 4、拿到群组用户信息
        $chatUserModel = model(ChatUserModel::class);
        $chatUserDataList = $chatUserModel
            ->where([
                'chat_global_id' => ['IN', join(',', $chatIds)],
                'is_leave' => "no",
            ])
            ->field("user_id,chat_global_id")
            ->select();


        // 获取会话成员信息（头像、名称）
        $userInfoMap = [];

        $chatUserData = [];
        if (!empty($chatUserDataList)) {
            $chatUserIds = [];
            foreach ($chatUserDataList as $chatUserDataItem) {
                if (!array_key_exists($chatUserDataItem['chat_global_id'], $chatUserData)) {
                    $chatUserData[$chatUserDataItem['chat_global_id']][] = $chatUserDataItem['user_id'];
                    $chatUserIds[] = $chatUserDataItem['user_id'];
                } else {
                    if (count($chatUserData[$chatUserDataItem['chat_global_id']]) <= 9) { //取前九个人的头像
                        $chatUserData[$chatUserDataItem['chat_global_id']][] = $chatUserDataItem['user_id'];
                        $chatUserIds[] = $chatUserDataItem['user_id'];
                    }
                }
            }
            $chatUserIds = array_unique($chatUserIds);
            $userInfo = $this->getChatUserInfo($chatUserIds);
            $userInfoMap = array_column($userInfo, null, 'id');
        }

        // 会话头像
        $resData = [];
        foreach ($userChatList as $userChat) {
            $lastMessage = $lastMessageList[$userChat['global_id']] ?? null;
            $lastMessage = !empty($lastMessage) ? CommonService::getFormatAttrData($this->messageModel, $lastMessage) : null;
            if ($replyMessageList && !empty($lastMessage['reply_message_id']) && $lastMessage['reply_message_id'] > 0) {
                $lastMessage['reply_message'] = $replyMessageList[$lastMessage['reply_message_id']];
            }
            if ($forwardMessageList && $lastMessage['content_type'] == 'forward') {
                $forwardMessageIdList = explode(',', $lastMessage['content']['forward_message_ids']);
                foreach ($forwardMessageIdList as $forwardMessageId) {
                    if (array_key_exists($forwardMessageId, $forwardMessageList)) {
                        // 预览合并转发消息体需要用户名称
                        if (empty($forwardMessageList[$forwardMessageId]['sender_name'])) {
                            $forwardMessageList[$forwardMessageId]['sender_name'] = $forwardMessageSenderList[$forwardMessageList[$forwardMessageId]['sender']] ?? null;
                        }
                        $lastMessage['forward_message'][] = $forwardMessageList[$forwardMessageId];
                    }
                }
            }
            // 最后聊天记录
            $tempData = [
                'id' => $userChat['chat_id'],
                'type' => $userChat['type'],
                'link_id' => $userChat['link_id'],
                'link_type' => $userChat['link_type'],
                'chat_global_id' => $userChat['global_id'],
                'config' => json_decode($userChat['config'], true),
                'mute' => $userChat['mute'],
                'favorite' => $userChat['favorite'],
                'avatar' => [],
                'name' => "",
                'count' => isset($chatUserData[$userChat['global_id']]) ? count($chatUserData[$userChat['global_id']]) : 0,
                'last_message' => !empty($lastMessage) ? $lastMessage : "",
                'unread_count' => array_key_exists($userChat['global_id'], $unreadCount) ? $unreadCount[$userChat['global_id']] : 0,
                'unread_chat_list' => $unreadChatList[$userChat['global_id']] ?? [],
                'edited_at' => $userChat['edited_at']
            ];

            switch ($userChat['type']) {
                case 'system':
                    // 系统组
                    $tempData['name'] = $userChat['name'];
                    break;
                case 'group':
                    // 聊天群组
                    $tempData['name'] = $userChat['name'];
                    $count = 0;
                    foreach ($chatUserData[$userChat['global_id']] as $chatItem) {
                        if ($count === 9) {
                            break;
                        }
                        if (!isset($userInfoMap[$chatItem])) {
                            continue;
                        }
                        $tmpAvatar = !empty($userInfoMap[$chatItem]['thumb']) ? $userInfoMap[$chatItem]['thumb'] : "";
                        $tempData['avatar'][] = $tmpAvatar;
                        $tempData['chat_icon_data'][] = [
                            "id" => $chatItem,
                            "name" => $userInfoMap[$chatItem]['name'],
                            "avatar" => $tmpAvatar
                        ];
                        $count++;
                    };
                    break;
                case 'one2one':
                default:
                    // 一对一聊天
                    $otherUserId = $this->getPrivateChatOtherId($currentUserId, $userChat['global_id']);
                    if (!empty($otherUserId) && isset($userInfoMap[$otherUserId])) {
                        $tempData['name'] = $userInfoMap[$otherUserId]['name'] ?? "";
                        $tmpAvatar = !empty($userInfoMap[$otherUserId]['thumb']) ? $userInfoMap[$otherUserId]['thumb'] : "";
                        $tempData['avatar'] = [$tmpAvatar];
                        $tempData['chat_icon_data'][] = [
                            "name" => $userInfoMap[$otherUserId]['name'],
                            "avatar" => $tmpAvatar,
                        ];
                        //如果用户为系统用户 那么就修正当前会话为system会话
                        $tempData['is_system'] = $userInfoMap[$otherUserId]['is_system'] ?? "no";
                    }
                    break;
            }
            $tempData['chat_avatar'] = $chatAvatarList[$userChat['chat_avatar_id']]['thumb'] ?? "";
            $resData[] = $tempData;
        }
        return [
            'chat_list' => $resData
        ];
    }

    /**
     * 获取未读消息
     * @param $currentUserId
     * @param $tenantId
     * @return int|object|Model|RelationModel
     * @throws \Exception
     */
    public function getUnreadMessageCount($currentUserId, $tenantId)
    {
        $unReadMessageModel = model(ChatUnreadMessageModel::class);
        $unreadCount = $unReadMessageModel
            ->join("chat_user on chat_unread_message.user_id = chat_user.user_id AND chat_unread_message.chat_global_id = chat_user.chat_global_id")
            ->join("chat on chat.global_id = chat_user.chat_global_id")
            ->where([
                'chat_user.user_id' => $currentUserId,
                "chat_user.mute" => 'no',
                "chat_user.is_leave" => 'no',
                "chat.is_delete" => 'no',
                'chat.link_type' => ['NOTIN', 'task_work_order,work_order_assistant']
            ])
            ->field("chat_unread_message.id")
            ->count();
        $taskWorkOrderChat = $this->getChatWithSystemNotifyUser($currentUserId, 'work_order_assistant');
        if (!empty($taskWorkOrderChat)) {
            list($taskWorkOrderChatUnread,) = $this->getChatUnreadData($taskWorkOrderChat, $currentUserId);
            $unreadCount += $taskWorkOrderChatUnread;
        }
        return !empty($unreadCount) ? $unreadCount : 0;
    }

    /**
     * 获取当前登录用户未读的会话列表
     * @param $userId
     * @return array
     */
    public function getUserUnreadChatList($userId)
    {
        $messageModel = model(MessageModel::class);

        try {
            // 获取当前用户关联的会话信息


            $chatModel = model(ChatModel::class);
            $userChatList = $chatModel
                ->join("__CHAT_USER__ ON chat.global_id = chat_user.chat_global_id", "LEFT")
                ->field('chat.name,chat.id as chat_id,chat.global_id,chat.type,chat.link_type,chat.link_id,chat_user.user_id,chat_user.chat_global_id,chat_user.config,(select id from message m where chat.global_id = m.chat_global_id order by sent_at desc limit 1) AS last_message_id')
                ->where([
                    'chat_user.user_id' => $userId,
                    'chat_user.is_leave' => "no",
                    'chat.is_delete' => 'no'
                ])
                ->select();

            $lastMessageIdData = array_filter(array_column($userChatList, 'last_message_id', 'last_message_id'), function ($item) {
                return (int)$item > 0;
            });

            $lastMessages = [];
            if (!empty($lastMessageIdData)) {
                $lastMessages = $messageModel->where(['id' => ['IN', implode(',', $lastMessageIdData)]])->selectData([
                    "fields" => "id,chat_global_id,content_type,content,sent_at,sender,status"
                ]);
                $lastMessages = array_column($lastMessages['rows'], null, 'id');
            }

            // 会话ids
            $chatIds = array_column($userChatList, 'global_id');

            // 未读消息的数量
            $chatUnreadMessageData = $this->getChatUnreadMessageData($userId, $chatIds);

            $charUnreadMessageDataMap = $this->generateIndexByKey($chatUnreadMessageData, 'chat_global_id');

            // 会话成员信息
            $chatUserData = $this->getChatUserData($chatIds);
            $charUserDataMap = [];
            if (!empty($chatUserData)) {
                $charUserDataMap = $this->generateIndexByKey($chatUserData, 'chat_global_id');
            }
            // 获取会话成员信息（头像、名称）
            $userInfoMap = [];
            if (!empty($chatUserData)) {
                $chatUserIds = array_column($chatUserData, 'user_id', 'user_id');
                $userInfo = $this->getChatUserInfo($chatUserIds);
                $userInfoMap = array_column($userInfo, null, 'id');
            }
            //所有未读消息数量（个人）
            $chatUserPrivateUnreadCount = 0;
            // 会话头像

            foreach ($userChatList as $ck => &$userChat) {
                // 最后聊天记录
                $lastMessage = $lastMessages[$userChat['last_message_id']] ?? null;
                $userChat['config'] = json_decode($userChat['config'], true);
                $userChat['avatar'] = [];
                $userChat['count'] = count($charUserDataMap[$userChat['global_id']]);
                $userChat['last_message'] = !empty($lastMessage) ? $lastMessage : [];
                $userChat['unread_count'] = array_key_exists($userChat['global_id'], $charUnreadMessageDataMap) ? count($charUnreadMessageDataMap[$userChat['global_id']]) : 0;
                switch ($userChat['type']) {
                    case 'system':
                        // 系统组
                        break;
                    case 'group':
                        // 聊天群组
                        $count = 0;
                        foreach ($charUserDataMap[$userChat['global_id']] as $chatItem) {

                            if (isset($userInfoMap[$chatItem['user_id']])) {
                                $tmpAvatar = !empty($userInfoMap[$chatItem['user_id']]['thumb']) ? $userInfoMap[$chatItem['user_id']]['thumb'] : "";
                                $userChat['avatar'][] = $tmpAvatar;
                                $tempData['chat_icon_data'][] = [
                                    "name" => $userInfoMap[$chatItem['user_id']]['name'] ?? "",
                                    "avatar" => $tmpAvatar,
                                ];
                                $count++;
                                if ($count === 9) {
                                    break;
                                }
                            } else {
                                continue;
                            }
                        }
                        break;
                    case 'one2one':
                    default:
                        // 一对一聊天
                        $otherUserId = $this->getPrivateChatOtherId($userId, $userChat['global_id']);
                        if (!empty($otherUserId) && isset($userInfoMap[$otherUserId])) {
                            $userChat['name'] = $userInfoMap[$otherUserId]['name'];
                            $tmpAvatar = empty($userInfoMap[$otherUserId]['thumb']) ? "" : $userInfoMap[$otherUserId]['thumb'];
                            $userChat['avatar'] = [$tmpAvatar];

                            $userChat['chat_icon_data'][] = [
                                "name" => $userInfoMap[$otherUserId]['name'] ?? "",
                                "avatar" => $tmpAvatar,
                            ];
                        } else {
                            // 用户丢失 就移除当前会话
                            unset($userChatList[$ck]);
                            break;
                        }
                        $chatUserPrivateUnreadCount += $userChat['unread_count'];
                        //如果用户为系统用户 那么就修正当前会话为system会话
                        $userChat['is_system'] = $userInfoMap[$otherUserId]['is_system'] ?? "no";
                }

            }
            return [
                "total_unread" => $chatUserPrivateUnreadCount,
                'chat_list' => array_values($userChatList)
            ];
        } catch (\Exception $exception) {
            throw_strack_exception($exception->getMessage(), $exception->getCode());
        }
    }

    /**
     * 获取会话未读消息
     * @param $currentUserId
     * @param array $param
     * @return array
     */
    public function getUserUnreadChatMessage($currentUserId, $param = [])
    {
        //会话ID
        $chatGlobalId = $param['param']['filter']['chat_global_id'];

        $chatUnreadMessageModel = model(ChatUnreadMessageModel::class);

        $charUnreadMessageData = $chatUnreadMessageModel->alias('cum')
            ->join('LEFT JOIN message ON cum.message_id=message.id')
            ->join('LEFT JOIN user ON user.id=message.sender')
            ->where(
                [
                    "cum.chat_global_id" => $chatGlobalId,
                    "cum.user_id" => $currentUserId
                ])
            ->field("message.id,user.name,user.id as user_id,message.sent_at,message.content,message.content_type")
            ->order(["id" => 'ASC'])
            ->select();

        if (empty($charUnreadMessageData)) {
            return [];
        }

        //如果是通知类型，直接返回记录列表
        if ($charUnreadMessageData[0]['content_type'] == 'notice') {
            return $charUnreadMessageData;
        }
        //从聊天记录中去找对应用户
        $userId = array_column($charUnreadMessageData, 'user_id', 'user_id');
        $userAvatar = [];
        if (!empty($userId)) {
            //获取头像
            $userAvatar = $this->getUsersAvatar($userId);
        }

        foreach ($charUnreadMessageData as $key => &$value) {
            $value['avatar'] = null;
            if (isset($userAvatar[$value['user_id']])) {
                $value['avatar'] = $userAvatar[$value['user_id']];
            }
            $value['content'] = !empty($value['content']) ? json_decode($value['content'], true) : [];
        }

        return $charUnreadMessageData;
    }

    /**
     * 会话基础信息
     * @param $currentUserId
     * @param $param
     * @return array
     */
    public function getBaseInfo($currentUserId, $param)
    {
        $chatModel = model(ChatModel::class);
        //会话基础信息
//        $data = $chatModel->where(['global_id' => $param['global_id']])->find();

        $queryFields = [
            "chat.name",
            "chat.id as chat_id",
            "chat.global_id",
            "chat.type",
            "chat.link_type",
            "chat.link_id",
            "chat_user.user_id",
            "chat_user.chat_global_id",
            "chat_user.config",
        ];
        $data = $chatModel
            ->join("chat_user ON chat_user.chat_global_id = chat.global_id", "LEFT")
            ->where([
                'chat_user.user_id' => $currentUserId,
                'chat_user.is_leave' => "no",
                'chat.global_id' => $param['global_id'],
            ])
            ->field(implode(",", $queryFields))
            ->find();
        if (empty($data)) {
            return [];
        }
        $chatUserModel = model(ChatUserModel::class);
        //会话用户人数
        $data['chat_user_count'] = $chatUserModel->where([
            'chat_global_id' => $param['global_id'],
            'is_leave' => "no",
        ])->count();
        $chatUser = $chatUserModel->where(['chat_global_id' => $param['global_id'], 'user_id' => $currentUserId])->find();
        $chatUsers = $chatUserModel->where(['chat_global_id' => $param['global_id']])->select();
        // 获取会话成员信息（头像、名称）
        $userInfoMap = [];
        if (!empty($chatUsers)) {

            $chatUserIds = array_column($chatUsers, 'user_id');
            $userInfo = $this->getChatUserInfo($chatUserIds);
            $userInfoMap = array_column($userInfo, null, 'id');
        }
        $chatUsers[$data['global_id']] = $chatUsers;
        $data = $this->formatChatData($currentUserId, $data, $chatUsers, $userInfoMap);
        if (!empty($chatUser)) {
            $data['allow_speak'] = $chatUser['allow_speak'];
            $data['is_admin'] = $chatUser['is_admin'];
            $data['config'] = json_decode($chatUser['config'], true);
        }
        return $data;
    }

    /**
     * 会话用户列表
     * @param $params
     * @param int $userId
     * @return mixed
     * @throws \Exception
     */
    public function getUserList($params, int $userId)
    {
        $activeTenant = model(TenantUserModel::class)->where(['user_id' => $userId, 'status' => 'active'])->field('tenant_id')->find();
        if (empty($activeTenant)) {
            throw_strack_exception("current user did`nt active an tenant", ErrorCode::CURRENT_USER_NOT_AT_THE_ACTIVE_TENANT);
        }

        $filter = $params['filter'];
        $fields = $params['fields'] ?? "user.id,user.name,user.phone,user.email,user.phone,user.sex,chat.from_tenant_id,chat.to_tenant_id";
        $order = $param['order'] ?? "chat_user.is_admin desc";
        $chatModel = model(ChatModel::class);
        $fields = explode(',', $fields);
        $newFields = [];
        foreach ($fields as $field) {
            $fieldData = explode('.', $field);
            if (isset($fieldData[0]) && $fieldData[0] === 'media') {
                continue;
            }
            $newFields[] = $field;
        }

        $userData = $chatModel->where($filter)
            ->join("chat_user ON chat.global_id = chat_user.chat_global_id")
            ->join("user ON chat_user.user_id = user.id")
            ->field(implode(',', $newFields))
            ->order($order)
            ->select();
        $tenantUserInfo = [];
        $userIdArray = array_column($userData, 'id');
        $userAvatar = [];
        if (!empty($userIdArray)) {
            //获取头像
            $userAvatar = $this->getUsersAvatar($userIdArray);
        }
        if (!empty($userIdArray)) {
            $tenantUserInfo = model(TenantUserModel::class)
                ->join("tenant ON tenant.id = tenant_user.tenant_id", "LEFT")
                ->where([
                    'tenant_user.user_id' => ['IN', implode(',', $userIdArray)],
                    'tenant_user.status' => 'active',
                ])
                ->field("tenant_user.id,tenant_user.user_id,tenant.name as tenant_name")
                ->select();
            $tenantUserDepartmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole(array_column($tenantUserInfo, 'id'));
            $tenantUserInfo = array_column($tenantUserInfo, null, 'user_id');
            foreach ($tenantUserInfo as &$item) {
                $item['department_info'] = $item['role_info'] = [];
                if (isset($tenantUserDepartmentRoleInfoList[$item['id']])) {
                    $item = array_merge($item, $tenantUserDepartmentRoleInfoList[$item['id']]);
                }
            }
        }
        foreach ($userData as &$userDatum) {
            $userDatum['info'] = $tenantUserInfo[$userDatum['id']] ?? null;
            $userDatum['thumb'] = $userDatum['avatar'] = $userAvatar[$userDatum['id']] ?? '';
        }
        return $userData;
    }

    /**
     * 获得一个一对一的会话
     * @param $receiver
     * @param $sender
     * @param $extraData
     * @return array|callable|mixed|string
     * @throws \Exception
     */
    public function getOneToOneChat($receiver, $sender, $extraData = [])
    {
        $type = 'one2one';
        if ($receiver > $sender) {
            $globalId = $sender . '&' . $receiver;
        } else {
            $globalId = $receiver . '&' . $sender;
        }
        $chatModel = model(ChatModel::class);

        $chat = $chatModel->where(['global_id' => $globalId])->find();

        if (!empty($chat)) {
            return $chat;
        }

        $data = [
            'data' => [//会话基础数据
                'name' => "私聊",
                'type' => $type,
                'created_by' => $sender,
                'global_id' => $globalId
            ],
            'receiver' => [$receiver],
            'sender' => $sender,
            'global_id' => $globalId
        ];

        $receiverData = model(UserModel::class)->find($receiver);
        if (empty($receiverData)) {
            throw new LogicException("missing receiver", ErrorCode::MISSING_RECEIVER);
        }

        // 避免重复创建
        $mutex = new PHPRedisMutex([Redis::connection()->client()], "onetoone_chat_create-$receiver-$sender");
        return $mutex->synchronized(function () use ($data, $extraData) {
            $chatModel = model(ChatModel::class);
            $chatUserModel = model(ChatUserModel::class);
            // 开启事务处理
            $chatModel->startTrans();

            try {
                // 新增会话基础信息
                $resData = $chatModel->addItem(array_merge($data['data'], $extraData));

                if (!$resData) {
                    $errorCode = !empty($chatModel->getErrorCode()) ? $chatModel->getErrorCode() : -202012;
                    if ($errorCode != \think\exception\ErrorCode::DATA_ALREADY_EXISTS) {
                        throw new LogicException($chatModel->getError(), $errorCode);
                    }
                    $resData = $chatModel->getCheckUniqueExitData();
                }

                //发送者合并至接受者成为会话成员
                array_push($data['receiver'], $data['sender']);
                foreach ($data['receiver'] as $userId) {
                    $chatUsers = [
                        'chat_global_id' => $data['global_id'],
                        'user_id' => $userId,
                        'is_admin' => 0,
                        'to_user_id' => $userId != $data['sender'] ? $data['sender'] : $userId,
                    ];
                    $chatUserResult = $chatUserModel->addItem($chatUsers);

                    if (!$chatUserResult) {
                        $errorCode = !empty($chatUserModel->getErrorCode()) ? $chatUserModel->getErrorCode() : -202012;
                        if ($errorCode != \think\exception\ErrorCode::DATA_ALREADY_EXISTS) {
                            throw new LogicException($chatUserModel->getError(), $errorCode);
                        }
                    }
                }
                $chatModel->commit();
                return $resData;
            } catch (\Throwable $e) {
                $chatModel->rollback();
                throw $e;
            }
        });
    }

    /**
     * 获得一个一对一的会话
     * @param array $receiverList
     * @param $sender
     * @param array $extraData
     * @return mixed
     * @throws \Exception
     */
    public function getOneToOneChatList(array $receiverList, $sender, $extraData = [])
    {
        $type = 'one2one';
        $globalIdMapList = [];
        foreach ($receiverList as $receiver) {
            if ($receiver == $sender) {
                throw new LogicException("cant` creat chat with yourself", ErrorCode::UNABLE_TO_CHAT_WITH_YOURSELF);
            }
            if ($receiver > $sender) {
                $globalId = $sender . '&' . $receiver;
            } else {
                $globalId = $receiver . '&' . $sender;
            }
            $globalIdMapList[$receiver] = $globalId;
        }
        $chatModel = model(ChatModel::class);
        $chatUserModel = model(ChatUserModel::class);

        $chatList = $chatModel->where(['global_id' => ['in', array_values($globalIdMapList)]])->select();

        if (count($chatList) === count($receiverList)) {
            return $chatList;
        }
        $existGlobalIdList = array_column($chatList, 'global_id');
        $resData = array_column($chatList, null, 'global_id');

        $dataList = [];
        $chatUserList = [];
        foreach ($globalIdMapList as $receiver => $globalId) {
            if (in_array($globalId, $existGlobalIdList)) {
                continue;
            }

            $chatUserList[$globalId] = [
                [
                    'chat_global_id' => $globalId,
                    'user_id' => $receiver,
                    'is_admin' => 0,
                    'to_user_id' => $sender,
                ],
                [
                    'chat_global_id' => $globalId,
                    'user_id' => $sender,
                    'is_admin' => 0,
                    'to_user_id' => $receiver,
                ]
            ];
            $dataList[] = [
                'data' => array_merge([//会话基础数据
                    'name' => "私聊",
                    'type' => $type,
                    'created_by' => $sender,
                    'global_id' => $globalId
                ], $extraData),
                'chat_users' => &$chatUserList[$globalId]
            ];
        }


        // 开启事务处理
        $chatModel->startTrans();

        try {
            foreach ($dataList as $data) {
                // 新增会话基础信息
                $flag = $chatModel->addItem($data['data']);
                if (!$flag) {
                    throw new LogicException($chatModel->getError(), $chatModel->getErrorCode());
                }
                $resData[$data['data']['global_id']] = $flag;
                // 添加会话成员
                foreach ($data['chat_users'] as $chatUser) {
                    $chatUserResult = $chatUserModel->add($chatUser);
                    if (!$chatUserResult) {
                        throw new LogicException($chatUserModel->getError(), $chatUserModel->getErrorCode());
                    }
                }
            }
            $chatModel->commit();
            return $resData;
        } catch (\Exception $e) {
            $chatModel->rollback();
            throw $e;
        }
    }


    /**
     * 创建会话
     * @param array $chat
     * @param array $chatUsers
     * @param int $ownerId
     * @return array
     * @throws \Exception
     */
    public function createChatAndChatUsers(array $chat, array $chatUsers, int $ownerId = 0)
    {
        $chatModel = model(ChatModel::class);
        $chatUserModel = model(ChatUserModel::class);
        $chat['global_id'] = $this->buildGlobalId($chat['type'], $chatUsers);

        // 开启事务处理
        $chatModel->startTrans();
        try {
            // 新增会话基础信息
            $resData = $chatModel->addItem($chat);
            if (!$resData) {
                throw new LogicException($chatModel->getError(), $chatModel->getErrorCode());
            }
            //发送者合并至接受者成为会话成员
            foreach ($chatUsers as $userId) {
                $isAdmin = $userId === $ownerId ? 1 : 0;
                $chatUsers = [
                    'chat_global_id' => $resData['global_id'],
                    'user_id' => $userId,
                    'is_admin' => $isAdmin
                ];
                $chatUserResult = $chatUserModel->addItem($chatUsers);
                if (!$chatUserResult) {
                    throw new LogicException($chatUserModel->getError(), $chatUserModel->getErrorCode());
                }
            }
            $chatModel->commit();
        } catch (\Exception $e) {
            $chatModel->rollback();
            throw $e;
        }
        return $resData;
    }

    /**
     * 生成chat global_id
     * @param string $type
     * @param array $chatUsers
     * @return mixed|string
     * @throws \Exception
     */
    private function buildGlobalId(string $type, array $chatUsers = [])
    {
        switch ($type) {
            case "one2one":
                if (!is_array($chatUsers) || count($chatUsers) != 2) {
                    throw new LogicException("one2one only support two chat user", ErrorCode::ONE2ONE_ONLY_SUPPORT_TWO_CHAT_USER);
                }
                list($u1, $u2) = array_values($chatUsers);
                if ($u1 > $u2) {
                    $res = $u2 . '&' . $u1;
                } else {
                    $res = $u1 . '&' . $u2;
                }
                break;
            case "group":
            default:
                $res = create_uuid();

        }
        return $res;
    }

    /**
     * 删除聊天
     * @param $param
     * @return array|int
     * @throws Exception|\Exception
     */
    public function deleteChat($param)
    {
        $chats = model(ChatModel::class)->where($param['filter'])->select();
        if (empty($chats)) {
            return [];
        }
        return model(ChatModel::class)->where(['id' => ['IN', array_column($chats, 'id')]])->save(['is_delete' => 'yes']);
    }


    /**
     * 创建租户聊天
     * @param $param
     * @return bool
     * @throws \Exception
     */
    public function createTenantChat($param)
    {
        $tenantModel = model(TenantModel::class);
        if (empty($param['param'])) {
            $tenants = $tenantModel->select();
        } else {
            $tenants = $tenantModel->selectData($param['param']);
            $tenants = $tenants['rows'];
        }
        $tenantService = new TenantService();
        foreach ($tenants as $tenant) {
            $tenantService->createCompanyChat($tenant['id'], 0);
        }
        return true;
    }

    /**
     * 项目聊天群
     * @param $param
     * @param int $currentUserId
     * @return mixed
     */
    public function projectChatList($param, int $currentUserId)
    {
        $chatModel = model(ChatModel::class);
        $tenantUserModel = model(TenantUserModel::class);
        $activeTenant = $tenantUserModel->where(['user_id' => $currentUserId, 'status' => 'active'])->field('tenant_id')->find();
        if (empty($activeTenant)) {
            throw_strack_exception("current user did`nt active an tenant", ErrorCode::CURRENT_USER_NOT_AT_THE_ACTIVE_TENANT);
        }

        $page = $param['param']['page'] ?? [1, 999];


        $queryFields = [
            "chat.name",
            "chat.id as chat_id",
            "chat.global_id",
            "chat.type",
            "chat.link_type",
            "chat.link_id",
            "chat_user.user_id",
            "chat_user.chat_global_id",
            "chat_user.config",
        ];

        $chatList = $chatModel
            ->join("chat_user ON chat_user.chat_global_id = chat.global_id", "LEFT")
            ->where([
                'chat_user.user_id' => $currentUserId,
                'chat_user.is_leave' => "no",
                'chat.link_type' => "project",
                "chat.from_tenant_id" => $activeTenant['tenant_id'],
                "chat.to_tenant_id" => $activeTenant['tenant_id'],
            ])
            ->field(implode(",", $queryFields))
            ->page($page[0], $page[1])
            ->select();


        $chatIds = array_column($chatList, 'global_id');
        $chatUserModel = model(ChatUserModel::class);
        $chatUserData = $chatUserModel
            ->where([
                'chat_global_id' => ['IN', join(',', $chatIds)],
                'is_leave' => "no",
            ])
            ->field("GROUP_CONCAT(distinct user_id) as user_ids,chat_global_id")
            ->group("chat_global_id")
            ->select();


        // 获取会话成员信息（头像、名称）
        $userInfoMap = [];
        if (!empty($chatUserData)) {
            $chatUserIds = [];

            $chatUserData = array_map(function ($item) use (&$chatUserIds) {
                $userIds = explode(',', $item['user_ids']);
                if (count($userIds)) {
                    $chatUserIds = array_merge($chatUserIds, array_slice($userIds, 0, 9));
                }
                $item['user_ids'] = array_map(function ($item) {
                    return [
                        'user_id' => $item
                    ];
                }, $userIds);
                return $item;
            }, $chatUserData);
            $chatUserData = array_column($chatUserData, 'user_ids', 'chat_global_id');
            $chatUserIds = array_unique($chatUserIds);
            $userInfo = $this->getChatUserInfo($chatUserIds);
            $userInfoMap = array_column($userInfo, null, 'id');
        }


        foreach ($chatList as &$chat) {
            $chat = $this->formatChatData($currentUserId, $chat, $chatUserData, $userInfoMap);
        }
        return $chatList;
    }

    /**
     * 外部聊天列表
     * @param $param
     * @param int $currentUserId
     * @return mixed
     */
    public function outSideChatList($param, int $currentUserId)
    {
        $chatModel = model(ChatModel::class);
        $tenantUserModel = model(TenantUserModel::class);
        $activeTenant = $tenantUserModel->where(['user_id' => $currentUserId, 'status' => 'active'])->field('tenant_id')->find();
        if (empty($activeTenant)) {
            throw_strack_exception("current user did`nt active an tenant", ErrorCode::CURRENT_USER_NOT_AT_THE_ACTIVE_TENANT);
        }

        $page = $param['param']['page'] ?? [1, 999];


        $queryFields = [
            "chat.name",
            "chat.id as chat_id",
            "chat.global_id",
            "chat.type",
            "chat.link_type",
            "chat.link_id",
            "chat_user.user_id",
            "chat_user.chat_global_id",
            "chat_user.config",
        ];

        $chatList = $chatModel
            ->join("chat_user ON chat_user.chat_global_id = chat.global_id", "LEFT")
            ->where([
                'chat_user.user_id' => $currentUserId,
                'chat_user.is_leave' => "no",
                "chat.from_tenant_id" => ["NEQ", $activeTenant['tenant_id'],],
                "chat.to_tenant_id" => $activeTenant['tenant_id'],
            ])
            ->field(implode(",", $queryFields))
            ->page($page[0], $page[1])
            ->select();


        $chatIds = array_column($chatList, 'global_id');
        $chatUserModel = model(ChatUserModel::class);
        $chatUserData = $chatUserModel
            ->where([
                'chat_global_id' => ['IN', join(',', $chatIds)],
                'is_leave' => "no",
            ])
            ->field("GROUP_CONCAT(distinct user_id) as user_ids,chat_global_id")
            ->group("chat_global_id")
            ->select();


        // 获取会话成员信息（头像、名称）
        $userInfoMap = [];
        if (!empty($chatUserData)) {
            $chatUserIds = [];

            $chatUserData = array_map(function ($item) use (&$chatUserIds) {
                $userIds = explode(',', $item['user_ids']);
                if (count($userIds)) {
                    $chatUserIds = array_merge($chatUserIds, array_slice($userIds, 0, 9));
                }
                $item['user_ids'] = array_map(function ($item) {
                    return [
                        'user_id' => $item
                    ];
                }, $userIds);
                return $item;
            }, $chatUserData);
            $chatUserData = array_column($chatUserData, 'user_ids', 'chat_global_id');
            $chatUserIds = array_unique($chatUserIds);
            $userInfo = $this->getChatUserInfo($chatUserIds);
            $userInfoMap = array_column($userInfo, null, 'id');
        }


        foreach ($chatList as &$chat) {
            $chat = $this->formatChatData($currentUserId, $chat, $chatUserData, $userInfoMap);
        }
        return $chatList;
    }


    /**
     * 解散群聊
     * @param $param
     * @param $userId
     * @return bool|float|int|string
     * @throws \Exception
     */
    public function disbandChat($param, $userId)
    {
        //验证是否是群主,才能解散
        $chatUserMine = model(ChatUserModel::class)->where([
            'chat_global_id' => $param['filter']['global_id'],
            'user_id' => $userId
        ])->field('is_admin')->find();

        $skipAdminCheck = $param['skip_admin_check'] ?? 'no';
        if (
            $skipAdminCheck === 'no'
            && (empty($chatUserMine) || $chatUserMine['is_admin'] != 1)) {
            throw_strack_exception("you are`nt admin,can`t disband chat", ErrorCode::ONLY_ADMINISTRATORS_CAN_DISBAND_CHAT);
        }

        $count = 0;
        if (!empty($param['filter'])) {
            $chat = ChatService::getInstance()->getChatDetail(['global_id' => $param['filter']['global_id']]);
            if (!empty($chat)) {
                $count = model(ChatModel::class)
                    ->where($param['filter'])
                    ->save([
                        'is_delete' => "yes",
                    ]);
                (new MessageService())->pushDisbandChatMessage($chat);
            }
        }


        return $count;
    }

    /**
     * 批量解散群聊
     * @param $param
     * @return bool|float|int|string
     * @throws \Exception
     */
    public function bathDisbandChat($param)
    {
        $count = 0;
        if (!empty($param['filter'])) {
            $chats = ChatService::getInstance()->getChatDetailAll(['global_id' => $param['filter']['global_id']]);
            if (!empty($chats)) {
                $count = model(ChatModel::class)
                    ->where($param['filter'])
                    ->save([
                        'is_delete' => "yes",
                    ]);
                (new MessageService())->pushBathDisbandChatMessage($chats);
            }
        }
        return $count;
    }

    /**
     * 删除聊天
     * @param $param
     * @return bool|float|int|string
     * @throws \Throwable
     */
    public function delete($param)
    {
        return model(ChatModel::class)
            ->where($param['filter'])
            ->save([
                'is_delete' => "yes",
            ]);
    }

    /**
     * 刷新会话的最后一次消息时间
     * @param $param
     * @return int
     * @throws \Exception
     */
    public function writeChatEditedAt($param)
    {
        $filter = $param['filter'] ?? [];
        $filter['is_delete'] = 'no';
        $trunkSize = 100;
        $page = 1;
        $changed = 0;
        while (true) {
            $chatList = model(ChatModel::class)->where($filter)->limit($trunkSize * ($page - 1), $trunkSize)->field('id,global_id,created,edited_at')->select();
            if (count($chatList) === 0) {
                break;
            }
            $chatGlobalIdList = array_column($chatList, 'global_id', 'global_id');
            $maxSendAtList = model(MessageModel::class)->where(['chat_global_id' => ['IN', $chatGlobalIdList]])->group('chat_global_id')->field('max(sent_at) as time,chat_global_id')->select();
            $maxSendAtList = array_column($maxSendAtList, 'time', 'chat_global_id');
            foreach ($chatList as $chat) {
                $lastSendAt = $maxSendAtList[$chat['global_id']] ?? 0;
                if (empty($lastSendAt)) {
                    $lastSendAt = $chat['created'];
                }
                if ($chat['edited_at'] === $lastSendAt) {
                    continue;
                }
                model(ChatModel::class)->save(['id' => $chat['id'], 'edited_at' => $lastSendAt]);
                $changed += 1;
            }
            $page += 1;
        }

        return $changed;
    }

    /**
     * 查找当前用户单个聊天
     * @param $filter
     * @param $findMethod
     * @param $currentUserId
     * @param $tenantId
     * @return array
     * @throws \Exception
     */
    public function findUserChat($filter, $findMethod, $currentUserId)
    {
        if ($findMethod === 'notify_user_mark') {
            $workOrderUser = UserService::getInstance()->getSystemNoticeUser($filter['notify_user_mark']);
            if (empty($workOrderUser)) {
                return null;
            }
            $workOrderChat = $this->getOneToOneChat($currentUserId, $workOrderUser['id'], ['link_type' => $filter['notify_user_mark'], 'edited_at' => time()]);
            $filter = ['id' => $workOrderChat['id']];
        }
        $chat = ChatService::getInstance()->getChatDetail($filter);


        if (empty($chat) || $chat['is_delete'] == 'yes') {
            return [];
        }

        $unreadCount = 0;
        $currentChatUser = model(ChatUserModel::class)->where(['chat_global_id' => $chat['global_id'], 'user_id' => $currentUserId])->field('mute,is_leave,favorite')->find();
        if (!empty($currentChatUser)) {
            list($unreadCount, $unreadChatList) = $this->getChatUnreadData($chat, $currentUserId);
            $chat['unread_chat_list'] = $unreadChatList;
        }

        $chat['unread_count'] = $unreadCount;

        $channelList = model(ChatUserModel::class)
            ->alias('cu')
            ->join('user AS u ON cu.user_id = u.id', "LEFT")
            ->field('cu.user_id')
            ->where(['chat_global_id' => $chat['global_id'], 'cu.is_leave' => "no"])
            ->select();

        $count = 0;
        if (!empty($channelList)) {
            if ($chat['type'] === "one2one") {// 一对一聊天
                $otherUserId = $this->getPrivateChatOtherId($currentUserId, $chat['global_id']);
                $userInfoMap = $this->getChatUserInfo([$otherUserId]);
                $userInfoMap = array_column($userInfoMap, null, 'id');
                $chat['name'] = $userInfoMap[$otherUserId]['name'] ?? "";
                $tmpAvatar = !empty($userInfoMap[$otherUserId]['thumb']) ? $userInfoMap[$otherUserId]['thumb'] : "";
                $chat['avatar'] = [$tmpAvatar];
                $chat['chat_icon_data'][] = [
                    "name" => $userInfoMap[$otherUserId]['name'],
                    "avatar" => $tmpAvatar,
                ];
                //如果用户为系统用户 那么就修正当前会话为system会话
                $chat['is_system'] = $userInfoMap[$otherUserId]['is_system'] ?? "no";
                $count = 2;
            } elseif ($chat['type'] === "group") {
                $userIds = array_column($channelList, 'user_id');
                $userAvatar = $this->getChatUserInfo(array_slice($userIds, 0, 9, false));
                $chat['avatar'] = array_column($userAvatar, 'thumb');
                foreach ($userAvatar as $userAvatarItem) {
                    $chat['chat_icon_data'][] = [
                        "id" => $userAvatarItem['id'],
                        "name" => $userAvatarItem['name'],
                        "avatar" => $userAvatarItem['thumb']
                    ];
                }
                $count = count($userIds);
            }

        }
        $chat['count'] = $count;

        $lastMessage = $this->getChatLatestMessage($chat, $currentUserId);
        $this->getChatLinkData($chat);
        $chat['last_message'] = $lastMessage;
        return $chat;
    }

    /**
     * 查询工单小助手的会话相关信息
     * @param int $currentUserId
     * @param $workOrderAssistantChat
     * @param array $unreadCount
     * @param array $lastMessageList
     * @param array $unreadChatList
     * @return void
     */
    private function getWorkOrderAssistantChatRelateInfo(int $currentUserId, $workOrderAssistantChat, array &$unreadCount, array &$lastMessageList, array &$unreadChatList)
    {
        list($unreadCount[$workOrderAssistantChat['global_id']], $unreadChatList[$workOrderAssistantChat['global_id']]) = $this->getChatUnreadData($workOrderAssistantChat, $currentUserId);
        $workOrderLastMessage = $this->messageModel
            ->where("chat_global_id in (select global_id from (select global_id from chat c join chat_user cu on cu.chat_global_id = c.global_id where c.link_type='task_work_order' and cu.user_id = {$currentUserId} order by c.edited_at desc limit 10 ) as t )")
            ->field('id,chat_global_id,content_type,content,sent_at,sender,status')
            ->order('id desc')
            ->find();

        if (!empty($workOrderLastMessage)) {
            $workOrderLastMessage['chat_global_id'] = $workOrderAssistantChat['global_id'];
            $lastMessageList[$workOrderAssistantChat['global_id']] = $workOrderLastMessage;
        } else {
            $lastMessageList[$workOrderAssistantChat['global_id']] = null;
        }
    }

    /**
     * 查询会话最后一条消息
     * @param $chat
     * @param $currentUserId
     * @return mixed|null
     */
    private function getChatLatestMessage($chat, $currentUserId)
    {
        $lastMessageFilter = [
            'chat_global_id' => $chat['global_id'],
        ];
        if ($chat['link_type'] === 'work_order_assistant') {
            $lastMessageFilter = "chat_global_id = (select global_id from chat c join chat_user cu on cu.chat_global_id = c.global_id where cu.user_id = {$currentUserId} order by c.edited_at desc limit 1 )";

        }
        $lastMessage = model(MessageModel::class)->where($lastMessageFilter)->field('id,chat_global_id,content_type,content,sent_at,sender,status')->order('id desc')->find();
        return !empty($lastMessage) ? CommonService::getFormatAttrData($this->messageModel, $lastMessage) : null;
    }

    /**
     * 查询会话未读信息
     * @param $chat
     * @param int $currentUserId
     * @return array
     */
    private function getChatUnreadData($chat, int $currentUserId)
    {
        $unreadChatList = [];
        $currentChatUser = model(ChatUserModel::class)->where(['chat_global_id' => $chat['global_id'], 'user_id' => $currentUserId])->field('mute,is_leave,favorite,chat_global_id')->find();
        $unreadCount = 0;
        if ($chat['link_type'] === 'work_order_assistant') {
            $unreadChatList = model(ChatUnreadMessageModel::class)
                ->alias('cum')
                ->join('chat c on c.global_id = cum.chat_global_id')
                ->join('chat_user cu on cu.chat_global_id = c.global_id')
                ->where(['c.link_type' => 'task_work_order', 'cum.user_id' => $currentUserId, 'cu.user_id' => $currentUserId,])
                ->where(['cu.is_leave' => 'no', 'c.is_delete' => 'no'])
                ->group('c.global_id')
                ->field('c.global_id')
                ->select();
            $unreadChatList = array_column($unreadChatList, 'global_id');
            if ($currentChatUser['mute'] != 'yes' && $currentChatUser['is_leave'] != 'yes') {
                $unreadCount = count($unreadChatList);
            }
        } else {
            if ($currentChatUser['mute'] != 'yes' && $currentChatUser['is_leave'] != 'yes') {
                $unreadCount = model(ChatUnreadMessageModel::class)->where(['chat_global_id' => $chat['global_id'], 'user_id' => $currentUserId])->count();
            }
        }

        return [$unreadCount, $unreadChatList];
    }

    /**
     * 查询与系统用户的会话
     * @param int $currentUserId
     * @param string $notifyUserMark
     * @return mixed|null
     * @throws \Exception
     */
    public function getChatWithSystemNotifyUser(int $currentUserId, string $notifyUserMark)
    {
        // 处理工单助手的最后一条
        $systemNoticeUser = UserService::getInstance()->getSystemNoticeUser($notifyUserMark);
        if (empty($systemNoticeUser)) {
            return null;
        }

        return $this->getOneToOneChat($currentUserId, $systemNoticeUser['id'], ['link_type' => $notifyUserMark, 'edited_at' => time()]);
    }

    /**
     * 查询会话关联数据
     * @param $chat
     * @return void
     */
    private function getChatLinkData(&$chat)
    {
        switch ($chat['link_type']) {
            case 'task_work_order':
                $chat['work_chat_list'] = Request::connection()
                    ->setHeader([
                        'X-Userinfo' => request()->getXUserInfo(),
                    ])
                    ->setServerHost('teamones-saas')
                    ->setRoute('task_work_order/find_task_work_order_chat')
                    ->setBody([
                        'param' => [
                            'filter' => [
                                'id' => $chat['link_id'],
                            ]
                        ]
                    ])
                    ->setMethod('POST')
                    ->request()['data'];
                break;
        }
    }

    /**
     * 更新会话的编辑时间
     * @param int $chatId
     * @param int $editedAt
     * @param bool $isUpdate
     * @return void
     * @throws \Exception
     */
    public function updateChatEditedAt(int $chatId, int $editedAt, bool $isUpdate = true)
    {
        $added = ChatEditedAtUpdateService::getInstance()->pushUpdateEvent($chatId, $editedAt, \request()->getXUserInfo());
        if ($added) {
            Client::send('update_chat_edited_at', build_queue_data_with_xu(['chat_id' => $chatId]), 10);
        }
    }

    /**
     * 更新工单助手的编辑时间
     * @param $chatGlobalId
     * @param int $editedAt
     * @return void
     * @throws \Exception
     */
    public function updateWorkOrderAssistantEditedAt($chatGlobalId, int $editedAt)
    {
        $receiver = model(ChatUserModel::class)->where(['chat_global_id' => $chatGlobalId])->column('user_id');
        $noticeUser = UserService::getInstance()->getSystemNoticeUser('work_order_assistant');
        if (empty($noticeUser)) {
            return;
        }
        $chatList = $this->getOneToOneChatList($receiver, $noticeUser['id'], ['link_type' => 'work_order_assistant', 'edited_at' => $editedAt]);
        if (empty($chatList)) {
            return;
        }
        foreach ($chatList as $chat) {
            $this->updateChatEditedAt($chat['id'], $editedAt);
        }
    }

    /**
     * 批量创建会话
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function batchCreateChat($param)
    {
        //["data"=>[['created_by'=>$userId1,'receiver'=>[$userId2,$userId3],'name'=>'名字','link_id'=>'123','link_type'=>'','created'=>'']]]

        $chatData = [];
        $chatUserData = [];
        $globalIds = [];
        foreach ($param['data'] as $dataItem) {
            if (count($dataItem['receiver']) === 1) {
                if ($dataItem['receiver'][0] == $dataItem['created_by']) {
                    continue;
                }
                $type = 'one2one';
                if ($dataItem['created_by'] > $dataItem['receiver'][0]) {
                    $globalId = $dataItem['receiver'][0] . '&' . $dataItem['created_by'];
                } else {
                    $globalId = $dataItem['created_by'] . '&' . $dataItem['receiver'][0];
                }
                $name = '私聊';
            } else {
                $type = 'group';
                $name = '群聊';
                $globalId = create_uuid();
            }
            //组装会话创建数据
            if (!isset($chatData[$globalId])) {
                $chatData[$globalId] = [
                    'global_id' => $globalId,
                    'type' => $type,
                    'name' => $name,
                    'created_by' => $dataItem['created_by'],
                    'link_type' => $dataItem['link_type'] ?? '',
                    'link_id' => $dataItem['link_id'] ?? 0,
                    'created' => $dataItem['created'] ?? time(),
                    'from_tenant_id' => $dataItem['from_tenant_id'] ?? 0,
                    'project_id' => $dataItem['project_id'] ?? 0,
                ];
                if (!empty($dataItem['name'])) {
                    $chatData[$globalId]['name'] = $dataItem['name'];
                }
            }


            if (!isset($chatUserData[$globalId])) {
                $chatUserData[$globalId] = [
                    'receiver' => $dataItem['receiver'],
                    'sender' => $dataItem['created_by'],
                    'global_id' => $globalId,
                    'type' => $type,
                ];
            }

            $globalIds[] = $globalId;
        }

        if (empty($globalIds)) {
            return [];
        }

        $globalIds = array_unique($globalIds);
        $chatModel = model(ChatModel::class);
        $chatUserModel = model(ChatUserModel::class);

        $chatList = $chatModel->field('*,global_id as chat_global_id')->where(['global_id' => ["IN", $globalIds]])->select();
        //找出未创建的群聊
        $chatGlobalId = array_column($chatList, 'global_id', 'global_id');
        $diffGlobal = array_diff_key($chatData, $chatGlobalId);

        if (!empty($diffGlobal)) {
            $chatUserData = array_intersect_key($chatUserData, $diffGlobal);

            $chatUsers = [];
            $chatReceiverMap = [];
            $chatAdminMap = [];
            $userIds = [];
            foreach ($chatUserData as $globalId => $chatUserDataItem) {
                //发送者合并至接受者成为会话成员
                $chatUserDataItem['receiver'][] = $chatUserDataItem['sender'];
                $chatUserDataItem['receiver'] = array_unique($chatUserDataItem['receiver']);
                //一对一
                if ($chatUserDataItem['type'] == 'one2one') {
                    $chatUsers[] = [
                        'chat_global_id' => $chatUserDataItem['global_id'],
                        'user_id' => $chatUserDataItem['receiver'][0],
                        'to_user_id' => $chatUserDataItem['receiver'][1],
                        'is_admin' => 0,
                        'join_at' => time()
                    ];

                    $chatUsers[] = [
                        'chat_global_id' => $chatUserDataItem['global_id'],
                        'user_id' => $chatUserDataItem['receiver'][1],
                        'to_user_id' => $chatUserDataItem['receiver'][0],
                        'is_admin' => 0,
                        'join_at' => time()
                    ];

                } else {
                    $chatAdminMap[$globalId] = $chatUserDataItem['sender'];
                    foreach ($chatUserDataItem['receiver'] as $userId) {
                        if ($userId != $chatUserDataItem['sender']) {
                            //去除掉自己
                            $chatReceiverMap[$globalId][] = $userId;
                        }

                        if (!in_array($userId, $userIds)) {
                            $userIds[] = $userId;
                        }
                        $isAdmin = 0;
                        //如果成员等于创建者且会话为群组，则为管理员
                        if ($userId === $chatUserDataItem['sender']) {
                            $isAdmin = 1;
                        }
                        $chatUsers[] = [
                            'chat_global_id' => $chatUserDataItem['global_id'],
                            'user_id' => $userId,
                            'is_admin' => $isAdmin,
                            'join_at' => time()
                        ];
                    }
                }
            }

            $diffGlobal = array_values($diffGlobal);

            // 开启事务处理
            $chatModel->startTrans();
            try {
                // 新增会话基础信息
                foreach (array_chunk($diffGlobal, 500) as $diffGlobalItem) {
                    $resData = $chatModel->addAll($diffGlobalItem);
                    if (!$resData) {
                        throw new LogicException($chatModel->getError(), $chatModel->getErrorCode());
                    }
                }

                foreach (array_chunk($chatUsers, 500) as $chatUsersItem) {
                    $chatUserResult = $chatUserModel->addAll($chatUsersItem);
                    if (!$chatUserResult) {
                        throw new LogicException($chatUserModel->getError(), $chatUserModel->getErrorCode());
                    }
                }

                $chatModel->commit();
                $diffGlobal['_logic'] = "OR";
                $resDataChat = $chatModel->where(['global_id' => ['IN', array_column($diffGlobal, 'global_id')]])->select();
                $resDataChatIds = [];
                foreach ($resDataChat as $resDataChatItem) {
                    $resDataChatIds[] = $resDataChatItem['id'];
                }
                try {
                    MessageService::getInstance()->batchPushNewChatMessage($resDataChatIds, $chatReceiverMap, $chatAdminMap, $userIds);
                } catch (\Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
                return array_merge($resDataChat, $chatList);
            } catch (\Exception $e) {
                $chatModel->rollback();
                throw_strack_exception($e->getMessage(), $e->getCode());
            }
        } else {
            return $chatList;
        }
    }

    /**
     * 获取会话是否存在未读
     * @param $filter
     * @param $userId
     * @return array
     */
    public function getChatIsUnread($filter, $userId)
    {
        $chat = model(ChatModel::class)->where($filter)->field("global_id,link_id")->select();

        if (empty($chat)) {
            return [];
        }

        $chatGlobalId = array_column($chat, 'global_id');
        $unreadList = model(ChatUnreadMessageModel::class)
            ->where([
                'chat_unread_message.chat_global_id' => ['IN', join(',', $chatGlobalId)],
                'chat_unread_message.user_id' => $userId
            ])
            ->field("chat_unread_message.chat_global_id")
            ->group('chat_unread_message.chat_global_id')
            ->select();

        $unreadChatGlobalIds = array_column($unreadList, 'chat_global_id');

        $chat = array_filter($chat, function ($chatItem) use ($unreadChatGlobalIds) {
            return in_array($chatItem["global_id"], $unreadChatGlobalIds);
        });
        return $chat;
    }

    /**
     * 获取会话详情
     * @param $filter
     * @return array|false|mixed|string|null
     */
    public function getChatDetail($filter)
    {
        return model(ChatModel::class)->where($filter)->field('*,global_id as chat_global_id')->find();
    }

    /**
     * 获取多条会话详情
     * @param $filter
     * @return array|false|mixed|string|null
     */
    public function getChatDetailAll($filter)
    {
        return model(ChatModel::class)->where($filter)->field('*,global_id as chat_global_id')->select();
    }

    /**
     * 更新群头像
     * @param $data
     * @param $currentUserId
     * @return array|bool|float|int|string
     * @throws \Exception
     */
    public function updateChatAvatar($data, $currentUserId)
    {
        $mediaModel = model(MediaModel::class);
        $chatData = model(ChatModel::class)->where(['global_id' => $data['chat_global_id']])->find();
        $chatData['chat_global_id'] = $data['chat_global_id'];
        if ($chatData['type'] != 'group') {
            throw_strack_exception("This conversation is not a group chat", ErrorCode::CHAT_IS_NOT_GROUP);
        }
        $chatUserData = model(ChatUserModel::class)->where(['chat_global_id' => $data['chat_global_id']])->select();
        $chatUserList = array_column($chatUserData, 'user_id');
        if (!in_array($currentUserId, $chatUserList)) {
            throw_strack_exception("User is not in chat", ErrorCode::CHAT_USER_NOT_FOUND);
        }
        $mediaService = new MediaService();
        $mediaService->generateMediaData($data['extra_file_media']);
        $mediaData = $mediaModel->addItem($data['extra_file_media']);
        if (!$mediaData) {
            throw_strack_exception("Chat avatar update failed:" . $mediaModel->getError(), ErrorCode::CHAT_AVATAR_FAILED);
        }
        model(ChatModel::class)->where(['global_id' => $data['chat_global_id']])->save(['chat_avatar_id' => $mediaData['id']]);
        // 更换头像需发送群通知给所有群成员（包括自己）
        $operateUser = model(UserModel::class)->field('id,name')->find($currentUserId);
        $userIdList = model(ChatUserModel::class)
            ->field('user_id')
            ->where([
                'chat_global_id' => $data['chat_global_id'],
                'is_leave' => "no"
            ])->column('user_id');
        $tmpMessage = [
            "chat_global_id" => $data['chat_global_id'],
            "type" => 'normal',
            'sender' => 0,
            'project_id' => 0,
            "content_type" => 'system_hint',
            "content" => [
                "type" => "upload_chat_avatar",
                "replace" => [
                    "operator" => $operateUser,
                    "chat_avatar" => $mediaData['thumb']
                ]
            ]
        ];
        $queueData = [
            'chat_global_id' => $chatData['global_id'],
            'message' => $tmpMessage,
            'user_id_list' => $userIdList,
        ];
        Client::send('send_system_hit_message', build_queue_data_with_xu($queueData));
        return $mediaData['thumb'];
    }

    /**
     * 查询制片小助手未读消息
     * @param int $userId
     * @return int[]
     * @throws \Exception
     */
    public function getProducerAssistantMessageUnReadCount(int $userId, $param = [])
    {
        $chat = $this->getChatWithSystemNotifyUser($userId, 'producer_assistant');
        if (empty($chat)) {
            throw new LogicException('chat not found', ErrorCode::CHAT_USER_NOT_FOUND);
        }
        $groupBaseKeys = [
            MessageModel::NOTIFY_TYPE_MESSAGE_DEMAND,
            MessageModel::NOTIFY_TYPE_MESSAGE_TASK,
            MessageModel::NOTIFY_TYPE_MESSAGE_REVIEW,
            MessageModel::NOTIFY_TYPE_MESSAGE_QA,
            MessageModel::NOTIFY_TYPE_MESSAGE_PRODUCER,
            MessageModel::NOTIFY_TYPE_MESSAGE_ORDER,
            MessageModel::NOTIFY_TYPE_MESSAGE_CAPACITY,
            MessageModel::NOTIFY_TYPE_APPROVAL,
            MessageModel::NOTIFY_TYPE_EXAMINE,
            MessageModel::NOTIFY_TYPE_TASK_REMIND,
            MessageModel::NOTIFY_TYPE_TODO,
            MessageModel::EVERYDAY_REPORT,
        ];
        $notifyTypeList = array_filter($param['notify_type_list'] ?? [], function ($item) use ($groupBaseKeys) {
            return in_array($item, $groupBaseKeys);
        });
        if (empty($notifyTypeList)) {
            return [];
        }
        $unreadMessageIdList = model(ChatUnreadMessageModel::class)
            ->where(['chat_unread_message.chat_global_id' => $chat['global_id'], 'chat_unread_message.user_id' => $userId])
            ->where(['chat_unread_message.notify_type' => ['IN', $notifyTypeList]])
            ->field([
                "count(*) as num",
                "chat_unread_message.notify_type"
            ])
            ->group('chat_unread_message.notify_type')
            ->select();
        $unreadMessageIdMap = array_column($unreadMessageIdList, null, 'notify_type');
        $returnData = [];
        $total = 0;
        foreach ($notifyTypeList as $type) {
            $returnData[$type] = $unreadMessageIdMap[$type]['num'] ?? 0;
            $total += $returnData[$type];
        }
        $returnData['total'] = $total;
        return $returnData;
    }

    /**
     * 会话是否存在消息
     * @param $filter
     * @return bool
     */
    public function hasMessage($filter)
    {
        $chat = model(ChatModel::class)->where($filter)->find();
        if (empty($chat)) {
            throw new LogicException('Chat not found', ErrorCode::CHAT_NOT_FOUND);
        }

        // 除开系统通知 是否有消息
        $messageExist = model(MessageModel::class)
            ->where(['chat_global_id' => $chat['global_id'], 'content_type' => ['NEQ', MessageModel::CONTENT_TYPE_SYSTEM_HINT]])
            ->find();

        return !empty($messageExist);
    }
}
